﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;

namespace ElGamalPublicEncryption
{
    //[Serializable]
    //public struct ElGamalKeys
    //{
    //    public byte[] P;
    //    public byte[] G;
    //    public byte[] Y;
    //    [NonSerialized]
    //    public byte[] X;
    //}

    public class ElGamalPublicKey
    {
        public BigInteger P;
        public BigInteger G;
    }

    public struct ElGamalKeys
    {
        
    }

    public class ElGamal : System.Security.Cryptography.AsymmetricAlgorithm
    {
        ElGamalKeys MyKeys;

        public ElGamal(ElGamalKeys myKeys)
        {
            this.MyKeys = myKeys;
        }

        public override void FromXmlString(string xmlString)
        {
            throw new NotImplementedException();
            //XmlTextReader reader = new XmlTextReader(new StringReader(xmlString));
            //while (reader.Read())
            //{
            //    if (reader.IsStartElement())
            //    {
            //        switch (reader.Name)
            //        {
            //            case "P":
            //                MyKeys.P = Convert.FromBase64String(reader.ReadString());
            //                break;
            //            case "G":
            //                MyKeys.G = Convert.FromBase64String(reader.ReadString());
            //                break;
            //            case "Y":
            //                MyKeys.Y = Convert.FromBase64String(reader.ReadString());
            //                break;
            //            case "X":
            //                MyKeys.X = Convert.FromBase64String(reader.ReadString());
            //                break;
            //        }
            //    }
            //}
        }

        public override string ToXmlString(bool includePrivateParameters)
        {
            throw new NotImplementedException();
            //StringBuilder x_sb = new StringBuilder();
            //x_sb.Append("<ElGamalKey>");
            //x_sb.Append("<P>" + Convert.ToBase64String(MyKeys.P) + "</P>");
            //x_sb.Append("<G>" + Convert.ToBase64String(MyKeys.G) + "</G>");
            //x_sb.Append("<Y>" + Convert.ToBase64String(MyKeys.Y) + "</Y>");
            //if (includePrivateParameters)
            //{
            //    x_sb.Append("<X>" + Convert.ToBase64String(MyKeys.X) + "</X>");
            //}
            //return x_sb.ToString();
        }

        public override string SignatureAlgorithm
        {
            get { throw new NotImplementedException(); }
        }

        public override string KeyExchangeAlgorithm
        {
            get { return "ElGamal"; }
        }

        public static void GenerateKeys(int keyStrength, ref ElGamalPublicKey publicKey, out BigInteger privateKey, out BigInteger Y)
        {
            Random pseudoRandomGenerator = new Random();
            
            if (publicKey == null)
            {
                // Create the large prime number(P), and the generator(G).
                publicKey = new ElGamalPublicKey
                                {
                                    P = BigInteger.genPseudoPrime(keyStrength, 16, pseudoRandomGenerator),
                                    G = new BigInteger()
                                };
                publicKey.G.genRandomBits(keyStrength - 1, pseudoRandomGenerator);
            }
            
            // private Key
            privateKey = new BigInteger();
            privateKey.genRandomBits(keyStrength - 1, pseudoRandomGenerator);
            // compute Y
            Y = publicKey.G.modPow(privateKey, publicKey.P);
        }

        public static void Mainx(string[] args)
        {
            ServerBegin();
            ClientBegin();

        }

        private static ElGamalPublicKey publicKey;
        private static BigInteger serverPrivateKey;
        private static BigInteger serverY;
        private static BigInteger clientPrivateKey;
        private static BigInteger clientY;

        private static void ServerBegin()
        {
            GenerateKeys(1024, ref publicKey, out serverPrivateKey, out serverY);
        }

        private static void ClientBegin()
        {
            GenerateKeys(1024, ref publicKey, out clientPrivateKey, out clientY);
        }

    }
}
